﻿import com.mochimedia.ui.*;

/**
 * ...
 * @author Geoff
 */
class com.mochimedia.ui.ASUIML {
    
    private static var _css:TextField.StyleSheet;
	
	private static var _defaultCSSTemplate:String = '
        h1 { font-family: "Verdana, Helvetica, Arial"; font-weight: bold; font-size: 18px; color: %titleColor%; leading: 0px; }     
        h2 { font-family: "Verdana, Helvetica, Arial"; font-weight: bold; font-size: 16px; color: %titleColor%; leading: 0px; }       
        h3 { font-family: "Verdana, Helvetica, Arial"; font-weight: bold; font-size: 14px; color: %titleColor%; leading: 0px; }
        h4 { font-family: "Verdana, Helvetica, Arial"; font-weight: bold; font-size: 13px; color: %titleColor%; leading: 0px; }
        p { font-family: "Verdana, Helvetica, Arial"; font-weight: normal; font-size: 12px; color: %textColor%; leading: 2px; }
        a { font-weight: bold; color: " + lColor + "; text-decoration: underline; }
        a:hover { font-weight: bold; color: #6699cc; textDecoration: underline; }
		';
    
    //
    //
    public static function setStyles (cssText:String):Void {
        
        if (cssText != undefined) {
            
            _css = new TextField.StyleSheet();
            _css.parseCSS(cssText);
            
        }
        
    }
    
    //
    //
	public static function createCSSObject (cssText:String, style:Style):TextField.StyleSheet {
        
        var css:TextField.StyleSheet;
		
        if (cssText != undefined) {

			cssText = _defaultCSSTemplate + "\n" + cssText.split("px").join("");
			
		} else {
			
			cssText = _defaultCSSTemplate;
			
		}
			
		var ttc:String = "#336699";
		var tc:String = "#000000";
		if (style != undefined) ttc = ColorTools.numberToHTMLColor(style.titleColor);
		if (style != undefined) tc = ColorTools.numberToHTMLColor(style.textColor);
		cssText = cssText.split("%titleColor%").join(ttc);
		cssText = cssText.split("%textColor%").join(tc);
		
		css = new TextField.StyleSheet();
		css.parseCSS(cssText);

		return css;
		
	}
    
    //
    //
    public static function create (obj:ASUIObject, xmlString:String, css:Object, style:Style):Void {
        
        var stylesheet:TextField.StyleSheet;
		
		if (css instanceof TextField.StyleSheet) stylesheet = TextField.StyleSheet(css);
		else stylesheet = createCSSObject(String(css), style);
        
		var xml:XML;

        if (xmlString != undefined) {

            xml = new XML();
            xml.ignoreWhite = true;
			xmlString = xmlString.split("event:").join("asfunction:dispatchlink,");
            xml.parseXML(xmlString);
            
            if (xml.status == 0) {
 
                if (css != undefined) buildNode(obj, obj.root, xml.firstChild, stylesheet, style);
                else buildNode(obj, obj.root, xml.firstChild, _css, style);
                
            } else {
                
                trace("ERROR PARSING XML: [code " + xml.status + "]");
                
            }
            
        }
        
    }
	
	
	//
	//
	private static function getCSSClass (xmlNode:XMLNode, css:TextField.StyleSheet):Object {
		
		var ss:Object = { };

		if (xmlNode.attributes["class"] != undefined) {
			var cssClass:Object = css.getStyle("." + xmlNode.attributes["class"]);
			if (cssClass != undefined) return cssClass;
		}
		
		return ss;
	
	}
	
	
	//
	//
	private static function getBounds (xmlNode:XMLNode, css:TextField.StyleSheet):Object {
		
		var w:Number;
		var h:Number;
		var bg:Boolean = false;
		var border:Boolean = false;
		var round:Number = 0;
		var ss:Object = getCSSClass(xmlNode, css);

		if (xmlNode.attributes.width != undefined) w = parseInt(xmlNode.attributes.width);
		else if (ss.width != undefined) w = parseInt(ss.width);
		
		if (xmlNode.attributes.height != undefined) h = parseInt(xmlNode.attributes.height);
		else if (ss.height != undefined) h = parseInt(ss.height);
		
		if (ss.background != undefined || xmlNode.attributes.background != undefined) bg = true;
		if (ss.border != undefined || xmlNode.attributes.border != undefined) border = true;
		if (ss.round != undefined) round = parseInt(ss.round);
		
		return { width: w, height: h, background: bg, border: border, round: round };
		
	}
	
	
	//
	//
	private static function getPosition (xmlNode:XMLNode, css:TextField.StyleSheet):Position {
		
		var ss:Object = getCSSClass(xmlNode, css);
		
		var top:Number = 0;
		var left:Number = 0;
		
		var options:Object = { };
		
		var textAlign:Number = (xmlNode.nodeName == "input" && xmlNode.attributes.type == "button") ? Position.ALIGN_CENTER : Position.ALIGN_LEFT;
		
		if (ss.textAlign != undefined) {
			if (ss.textAlign == "left") textAlign = Position.ALIGN_LEFT;
			if (ss.textAlign == "center") textAlign = Position.ALIGN_CENTER;
			if (ss.textAlign == "right") textAlign = Position.ALIGN_RIGHT;
		}
		
		var placement:Number = Position.PLACEMENT_NORMAL;
		
		if (ss.position != undefined && ss.position == "absolute") {
			placement = Position.PLACEMENT_ABSOLUTE;
			if (ss.top != undefined) top = parseInt(ss.top);
			if (ss.left != undefined) left = parseInt(ss.left);
		} else if (ss.float != undefined) {
			if (ss.float == "left") placement = Position.PLACEMENT_FLOAT;
			if (ss.float == "right") placement = Position.PLACEMENT_FLOAT_RIGHT;
		}
		
		var clear:Number = (placement == Position.PLACEMENT_NORMAL) ? Position.CLEAR_BOTH : Position.CLEAR_NONE;
		if (ss.clear != undefined) {
			if (ss.clear == "left") clear = Position.CLEAR_LEFT;
			if (ss.clear == "right") clear = Position.CLEAR_RIGHT;
			if (ss.clear == "both") clear = Position.CLEAR_BOTH;
		}
		
		var margins:Object;
		if (ss.margins != undefined) margins = (ss.margins.indexOf(" ") != -1) ? ss.margins : parseInt(ss.margins);
		if (margins == NaN) margins = undefined;
		if (ss.marginTop != undefined) options.margin_top = parseInt(ss.marginTop);
		if (ss.marginRight != undefined) options.margin_right = parseInt(ss.marginRight);
		if (ss.marginBottom != undefined) options.margin_bottom = parseInt(ss.marginBottom);
		if (ss.marginLeft != undefined) options.margin_left = parseInt(ss.marginLeft);
		
		var collapse:Boolean = (isNaN(getBounds(xmlNode, css).height));
		
		if (ss.collapse == "true") collapse = true;

		return new Position(options, textAlign, placement, clear, margins, top, left, null, collapse);

	}
	
	//
	//
	private static function getStyle (xmlNode:XMLNode, css:TextField.StyleSheet, html:Boolean, style:Style):Style {
		
		var s:Style;
		
		if (style != undefined) s = style.clone();
		else s = new Style();
		
		var ss:Object = getCSSClass(xmlNode, css);
		
		if (html) {
			
			var ac:String = css.getStyle("a").color;
			var ahc:String = css.getStyle("a:hover").color;
			var pc:String = css.getStyle("p").color;
			
			if (ac != undefined) s.linkColor = ColorTools.HTMLColorToNumber(ac);
			if (ahc != undefined) s.hoverColor = ColorTools.HTMLColorToNumber(ahc);
			if (pc != undefined) s.textColor = ColorTools.HTMLColorToNumber(pc);
			
			s.styleSheet = css;
			
		} else {
		
			if (xmlNode.nodeName == "input" && xmlNode.attributes.type == "button") {
				if (ss.backgroundColor != undefined) s.buttonColor = ColorTools.HTMLColorToNumber(ss.backgroundColor);
				if (ss.color != undefined) s.textColor =  ColorTools.getInverseColor(ColorTools.HTMLColorToNumber(ss.color));
				if (ss.background == "false") s.background = false;
				if (ss.gradient == "false") s.gradient = false;
			} else {
				if (ss.backgroundColor != undefined) s.backgroundColor = ColorTools.HTMLColorToNumber(ss.backgroundColor);
			if (ss.color != undefined) s.titleColor = s.textColor = ColorTools.HTMLColorToNumber(ss.color);
			}
			if (ss.border == "false") s.border = false;
			if (ss.fontSize != undefined) s.fontSize = parseInt(ss.fontSize);
			if (ss.borderWidth != undefined) s.borderWidth = ss.borderWidth;
			if (ss.borderColor != undefined) s.borderColor = ColorTools.HTMLColorToNumber(ss.borderColor);
		}
		
		return s;
		
	}
    
    //
    //
	private static function checkVisibility (xmlNode:XMLNode, css:TextField.StyleSheet):Boolean {
	
		var ss:Object = getCSSClass(xmlNode, css);
		
		if ((ss.visibility != undefined && ss.visibility == "hidden") ||
			(ss.display != undefined && ss.display == "none")) {
				
				return false;
				
			}
		
		return true;
		
	}
    
    //
    //
    private static function buildNode (obj:ASUIObject, container:Cell, xmlNode:XMLNode, css:TextField.StyleSheet, style:Style):Void {
        
        var n:XMLNode = xmlNode;
        var a:Object = xmlNode.attributes;
        var nc:Component;
		var bounds:Object;
		var s:Style;
		var p:Position;

        if (container != undefined && n != undefined) {
 
            switch (n.nodeName) {
                
				case "label":
				case "a":
					
					if (xmlNode.firstChild != null) buildNode(obj, container, xmlNode.firstChild, css, style);
					break;
				
                case "div":		
               
					bounds = getBounds(n, css);
					s = getStyle(n, css, false, style);
					p = getPosition(n, css);

                    nc = container.addChild(new Cell(null, bounds.width, bounds.height, bounds.background, bounds.border, bounds.round, p, s));
                    
                    if (xmlNode.firstChild != null) buildNode(obj, Cell(nc), xmlNode.firstChild, css, style); 
                    
					if (p.collapse == true) Cell(nc).update();
                    break;
					
				case "p":
				case "h1":
				case "h2":
				case "h3":
				case "h4":
				case "h5":
				case "li":
				case "ul":
				case "ol":

					bounds = getBounds(n, css);
					s = getStyle(n, css, true, style);
					p = getPosition(n, css);
					
					nc = container.addChild(new HTMLField(null, n.toString(), bounds.width, (bounds.height == undefined || bounds.height > 20), p, s));
					obj.connectHTMLField(HTMLField(nc));
					if (bounds.height != undefined) nc.height = bounds.height;
					break;
					
				case "hr":
				
					bounds = getBounds(n, css);
					s = getStyle(n, css, false, style);
					p = getPosition(n, css);
					
					nc = container.addChild(new HRule(null, bounds.width, p, s));
					break;
					
				case "asui:divider":
				
					bounds = getBounds(n, css);
					s = getStyle(n, css, false, style);
					p = getPosition(n, css);
					
					nc = container.addChild(new Divider(null, bounds.height, p, s));
					break;
					
				case "img":
				
					bounds = getBounds(n, css);
					s = getStyle(n, css, false, style);
					p = getPosition(n, css);
					
					nc = container.addChild(new Clip(null, a.src, Clip.EMBED_SMART, bounds.width, bounds.height, Clip.SCALEMODE_STRETCH, 
						(n.parentNode.nodeName == "a" && n.parentNode.attributes.href != undefined) ? n.parentNode.attributes.href : "",
						(n.parentNode.nodeName == "a" && n.parentNode.attributes.target == "_blank"),
						(n.attributes.alt != undefined) ? n.attributes.alt : "", p, s));
					break;
                
                case "input":
                
                    switch (a.type) {
                    
                        case "hidden":
                            break;
                            
                        case "submit":
                        case "button":
                        
							bounds = getBounds(n, css);
							s = getStyle(n, css, false, style);
							p = getPosition(n, css);
							
                            nc = container.addChild(
                                new BButton(
                                    null,
                                    (a.value != undefined) ? a.value : (a.icon != undefined) ? Create[a.icon] : "", 
									p.align, bounds.width, bounds.height, false, false, false, p, s
                                )
                            );
                            
							if (a.readonly == "true" || a.disabled == "true") BButton(nc).disable();
							
                            break;
                                
                        case "checkbox":
                        
							bounds = getBounds(n, css);
							s = getStyle(n, css, false, style);
							p = getPosition(n, css);
							
                            nc = container.addChild(
                                new CheckBox(
                                    null,
                                    (n.parentNode.nodeName == "label" && n.nextSibling.nodeValue != null) ? n.nextSibling.nodeValue : "",
                                    (a.value != undefined) ? a.value : "", (a.checked == "checked"),
									bounds.width, bounds.height, p, s
                                )
                            );
                        
							if (a.readonly == "true" || a.disabled == "true") CheckBox(nc).disable();
                        
                            break;
                            
                        case "radio":
						
							bounds = getBounds(n, css);
							s = getStyle(n, css, false, style);
							p = getPosition(n, css);
							
                            nc = container.addChild(
                                new RadioButton(
                                    null,
                                    (n.parentNode.nodeName == "label" && n.nextSibling.nodeValue != null) ? n.nextSibling.nodeValue : "",
                                    (a.value != undefined) ? a.value : "",
                                    (a.name != undefined) ? a.name : "", (a.checked == "checked"),
									bounds.width, bounds.height, p, s
                                )
                            );
                      
							if (a.readonly == "true" || a.disabled == "true") RadioButton(nc).disable();
                      
                            break;
                            
                        case "text":
                        default:
                        
							bounds = getBounds(n, css);
							s = getStyle(n, css, false, style);
							p = getPosition(n, css);
							
                            nc = container.addChild(
                                new FormField(
                                    null, 
                                    (a.value != undefined) ? a.value : "",
									bounds.width, bounds.height, (a.readonly != "true"), p, s
                                )
                            );
                                
							if (a.readonly == "true" || a.disabled == "true") FormField(nc).disable();
							
                            break;
                                                       
                    }
                    
                    break;
                    
                case "select":
                    
                    var choices:Array = [];
                    
                    var cx:Array = n.childNodes;
                    var cxidx:Number = 0;
                    for (var cs:Number = 0; cs < cx.length; cs++) {
                        choices.push(cx.attributes.value);
                        if (cx.attributes.selected != undefined) cxidx = cs; 
                    }
					
					bounds = getBounds(n, css);
					s = getStyle(n, css, false, style);
					p = getPosition(n, css);
                    
                    nc = container.addChild(
                        new ComboBox(
                            null, 
                            (n.parentNode.nodeName == "label" && n.nextSibling.nodeValue != null) ? n.nextSibling.nodeValue : "",
                            choices, 
                            cxidx,
                            (n.parentNode.nodeName == "label" && n.nextSibling.nodeValue != null) ? n.nextSibling.nodeValue : "",
							bounds.width, p, s
                        )
                    );
                    
                    break;
                
            }
            
            if (nc != undefined && a.id != undefined) {
                
                obj.idMap[a.id] = nc;
				nc.id = a.id;
                
            }
            
            if (nc != undefined && a.name != undefined) {

                nc.name = a.name;
				obj.nameMap[a.name] = nc;
				if (a.value != undefined) nc.value = a.value;
                obj.connect(nc);
                
            }

			if (nc != undefined && !checkVisibility(n, css)) nc.hide();
			
            if (xmlNode.nextSibling != null) {
				buildNode(obj, container, xmlNode.nextSibling, css, style); 
			}
            
        }
        
    }
    
}